package com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.OrgUserStuUtil;
import com.xyht.sca_s.student_manage_system.modules.chargePayment.entity.SmsWnsChargePaymentRecord;
import com.xyht.sca_s.student_manage_system.modules.chargePayment.entity.req.PaymentCategoryDivideReq;
import com.xyht.sca_s.student_manage_system.modules.chargePayment.entity.req.SmsWnsChargePaymentRecordReq;
import com.xyht.sca_s.student_manage_system.modules.chargePayment.mapper.SmsWnsChargePaymentRecordMapper;
import com.xyht.sca_s.student_manage_system.modules.common.constant.TaskNameExample;
import com.xyht.sca_s.student_manage_system.modules.common.constant.TaskTypeConstant;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTask;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskMapper;
import com.xyht.sca_s.student_manage_system.modules.signUp.constant.SmsSignUpCommonConstant;
import com.xyht.sca_s.student_manage_system.modules.student.entity.SmsStudentInfo;
import com.xyht.sca_s.student_manage_system.modules.student.mapper.SmsStudentInfoMapper;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.entity.*;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.entity.req.LoanAddReq;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.entity.req.LoanBatchAddReq;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.entity.req.SmsWnsStudentLoanAmountReq;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.entity.req.StudentLoanAmountExportReq;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.entity.resp.SmsWnsChargePlanStudentStatusResp;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.entity.resp.SmsWnsStudentLoanAmountResp;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.mapper.*;
import com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.service.SmsWnsStudentLoanAmountService;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.chargePayment.constant.SmsWnsChargePaymentRecordConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.*;
import static com.xyht.sca_s.student_manage_system.modules.signUp.constant.SmsSignUpCommonConstant.PER_SHEET_NUM;
import static com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.constant.RegistrationProcessDetailConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.welcomeNewStudent.constant.StudentLoanAmountRecordConstant.*;

/**
 * <p>
 * 学生助学贷款金额表 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2024-03-24
 */
@Service
public class SmsWnsStudentLoanAmountServiceImpl extends ServiceImpl<SmsWnsStudentLoanAmountMapper, SmsWnsStudentLoanAmount> implements SmsWnsStudentLoanAmountService {

    @Resource
    private SmsWnsChargePlanStudentStatusMapper smsWnsChargePlanStudentStatusMapper;
    @Resource
    private SmsWnsRegistrationProcessDetailMapper smsWnsRegistrationProcessDetailMapper;
    @Resource
    private SmsWnsChargePlanMapper smsWnsChargePlanMapper;
    @Resource
    private SmsWnsChargeCategoryMapper smsWnsChargeCategoryMapper;
    @Resource
    private SmsWnsChargeCategoryDetailMapper smsWnsChargeCategoryDetailMapper;
    @Resource
    private SmsStudentInfoMapper smsStudentInfoMapper;
    @Resource
    private OrgUserStuUtil orgUserStuUtil;
    @Resource
    private SmsImportTaskMapper smsImportTaskMapper;
    @Resource
    private SmsImportTaskDetailMapper smsImportTaskDetailMapper;
    @Resource
    private PlatformTransactionManager platformTransactionManager;
    @Resource
    private SmsWnsStudentLoanAmountRecordMapper smsWnsStudentLoanAmountRecordMapper;
    @Resource
    private SmsWnsChargePaymentRecordMapper smsWnsChargePaymentRecordMapper;

    @Override
    @Transactional
    public ResponseResult divideStudentLoanAmount(SmsWnsChargePaymentRecordReq req, String userId) {
        List<PaymentCategoryDivideReq> divideReqList = req.getDivideReqList();
        if (divideReqList.isEmpty()) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        // 校验学生助学贷款信息是否存在
        SmsWnsStudentLoanAmount studentLoanAmount = this.getOne(new LambdaQueryWrapper<SmsWnsStudentLoanAmount>()
                .eq(SmsWnsStudentLoanAmount::getUserId, userId));
        if (studentLoanAmount == null) {
            return CommonResult.failed(CommonCodeEnum.WNS_STUDENT_LOAN_AMOUNT_NOT_EXIST);
        }

        // 获取各收费项
        List<String> statusIdList = divideReqList.stream().map(PaymentCategoryDivideReq::getStudentStatusId).collect(Collectors.toList());
        List<SmsWnsChargePlanStudentStatus> statusList = smsWnsChargePlanStudentStatusMapper.selectBatchIds(statusIdList);
        if (statusList.size() != statusIdList.size()) {
            return CommonResult.failed(CommonCodeEnum.WNS_PLAN_STUDENT_STATUS_MISSING);
        }

        // 校验是否属于同一个计划
        List<String> planIdList = statusList.stream().map(SmsWnsChargePlanStudentStatus::getPlanId).distinct().collect(Collectors.toList());
        if (planIdList.size() != 1) {
            return CommonResult.failed(CommonCodeEnum.WNS_PLAN_STUDENT_STATUS_NOT_BELONG_SAME_PLAN);
        }

        // 校验计划是否存在
        String planId = planIdList.get(0);
        SmsWnsChargePlan plan = smsWnsChargePlanMapper.selectById(planId);
        if (plan == null || !plan.getIsPublish()) { // 计划不存在或未发布
            return CommonResult.failed(CommonCodeEnum.WNS_CHARGE_PLAN_NOT_EXIST);
        }

        // 校验计划是否已暂停
        if (plan.getIsPause()) {
            return CommonResult.failed(CommonCodeEnum.WNS_CHARGE_PLAN_PAUSE);
        }

        // 计算总金额
        BigDecimal totalAmount = new BigDecimal(0); // 付款总金额
        for (PaymentCategoryDivideReq divideReq : divideReqList) {
            // 获取对应的收费项
            SmsWnsChargePlanStudentStatus studentStatus = statusList.stream().filter(status -> status.getId().equals(divideReq.getStudentStatusId())).collect(Collectors.toList()).get(0);
            // 校验之前是否选择本项,未选择则修改本项
            if (!studentStatus.getIsNecessary()) {
                studentStatus.setIsNecessary(true); // 选择此项
            }

            // 校验贷款分配金额
            if (divideReq.getLoanAmount().compareTo(BigDecimal.valueOf(0)) < 0 // 贷款分配金额小于等于0
                    || divideReq.getLoanAmount().compareTo(studentStatus.getNeedPaymentAmount()) > 0) { // 贷款分配金额 > 欠费金额
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.WNS_PAYMENT_DIVIDE_AMOUNT_ILLEGAL));
            }

            // 设置助学金分配金额
//            studentStatus.setGrantAmount(divideReq.getLoanAmount());
            studentStatus.setGrantAmount(studentStatus.getGrantAmount().add(divideReq.getLoanAmount()));
            // 设置欠费金额(欠费金额 = 当前欠费金额 - 助学金分配金额)
            BigDecimal needPaymentAmount = studentStatus.getNeedPaymentAmount().subtract(divideReq.getLoanAmount());
            studentStatus.setNeedPaymentAmount(needPaymentAmount);
            if (needPaymentAmount.compareTo(BigDecimal.valueOf(0)) <= 0) {
                studentStatus.setIsPaid(true); // 设置当前缴费项为已交齐
            }
            smsWnsChargePlanStudentStatusMapper.updateById(studentStatus);

            totalAmount = totalAmount.add(divideReq.getLoanAmount());
        }

        // 获取当前助学贷款余额
        BigDecimal loanAmount = studentLoanAmount.getLoanAmount();
        // 校验贷款金额是否足够
        if (totalAmount.compareTo(loanAmount) > 0) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.WNS_STUDENT_LOAN_AMOUNT_NOT_ENOUGH));
        }

        // 修改余额
        studentLoanAmount.setLoanAmount(loanAmount.subtract(totalAmount));
        // 修改已使用金额
        studentLoanAmount.setUsedAmount(studentLoanAmount.getUsedAmount().add(totalAmount));
        // 设置分配项
        if (isNullOrEmpty(studentLoanAmount.getStatusIdList())) {
            studentLoanAmount.setStatusIdList(JSON.toJSONString(statusIdList));
        } else {
            List<String> oldStatusIdList = JSON.parseArray(studentLoanAmount.getStatusIdList(), String.class);
            oldStatusIdList.addAll(statusIdList); // 添加收费项
            List<String> newStatusIdList = oldStatusIdList.stream().distinct().collect(Collectors.toList()); // 去重并收集
            studentLoanAmount.setStatusIdList(JSON.toJSONString(newStatusIdList));
        }
        this.updateById(studentLoanAmount);

        // 添加学生助学贷款金额变动记录
        SmsWnsStudentLoanAmountRecord loanAmountRecord = new SmsWnsStudentLoanAmountRecord();
        loanAmountRecord.setLoanId(studentLoanAmount.getId());
        loanAmountRecord.setUserId(studentLoanAmount.getUserId());
        loanAmountRecord.setStuId(studentLoanAmount.getStuId());
        loanAmountRecord.setType(STUDENT_LOAN_AMOUNT_RECORD_TYPE_LOAN_AMOUNT);
        loanAmountRecord.setAmount(totalAmount.negate()); // 分配总金额的相反数
        loanAmountRecord.setNote(STUDENT_LOAN_AMOUNT_RECORD_DES_USE_LOAN_AMOUNT);
        smsWnsStudentLoanAmountRecordMapper.insert(loanAmountRecord);

        // 新生缴费设置新生该流程为进行中
        List<SmsWnsRegistrationProcessDetail> detailList = smsWnsRegistrationProcessDetailMapper.selectList(new LambdaQueryWrapper<SmsWnsRegistrationProcessDetail>()
                .eq(SmsWnsRegistrationProcessDetail::getUserId, userId)
                .eq(SmsWnsRegistrationProcessDetail::getSort, REGISTRATION_PROCESS_DETAIL_SORT_TWO) // 财务处报道
                .eq(SmsWnsRegistrationProcessDetail::getStatus, REGISTRATION_PROCESS_DETAIL_STATUS_NOT_START) // 未开始
                .orderByDesc(SmsWnsRegistrationProcessDetail::getCreateTime));
        if (!detailList.isEmpty()) {
            SmsWnsRegistrationProcessDetail detail = detailList.get(0);
            detail.setStatus(REGISTRATION_PROCESS_DETAIL_STATUS_START); // 设置为进行中
            smsWnsRegistrationProcessDetailMapper.updateById(detail);
        }

        return CommonResult.success();
    }

    @Override
    public ResponseResult ownDetail(String userId) {
        // 校验学生助学贷款信息是否存在
        SmsWnsStudentLoanAmount studentLoanAmount = this.getOne(new LambdaQueryWrapper<SmsWnsStudentLoanAmount>()
                .eq(SmsWnsStudentLoanAmount::getUserId, userId));
        if (studentLoanAmount == null) {
            return CommonResult.failed(CommonCodeEnum.WNS_STUDENT_LOAN_AMOUNT_NOT_EXIST);
        }

        SmsWnsStudentLoanAmountResp loanAmountResp = new SmsWnsStudentLoanAmountResp();
        BeanUtils.copyProperties(studentLoanAmount, loanAmountResp);

        SmsStudentInfo studentInfo = smsStudentInfoMapper.selectById(studentLoanAmount.getStuId());
        if (studentInfo != null) {
            loanAmountResp.setStudentInfo(studentInfo);
        }

        if (!isNullOrEmpty(studentLoanAmount.getStatusIdList())) {
            List<String> statusIdList = JSON.parseArray(studentLoanAmount.getStatusIdList(), String.class);
            List<SmsWnsChargePlanStudentStatus> studentStatusList = smsWnsChargePlanStudentStatusMapper.selectBatchIds(statusIdList);

            List<SmsWnsChargePlanStudentStatusResp> statusRespList = studentStatusList.stream().map(status -> {
                SmsWnsChargePlanStudentStatusResp statusResp = new SmsWnsChargePlanStudentStatusResp();
                BeanUtils.copyProperties(status, statusResp);

                SmsWnsChargePlan plan = smsWnsChargePlanMapper.selectAllById(status.getPlanId());
                if (plan != null) {
                    statusResp.setPlanName(plan.getName());
                }

                SmsWnsChargeCategory chargeCategory = smsWnsChargeCategoryMapper.selectAllById(status.getCategoryId());
                if (chargeCategory != null) {
                    statusResp.setCategory(chargeCategory);
                }

                SmsWnsChargeCategoryDetail categoryDetail = smsWnsChargeCategoryDetailMapper.selectAllById(status.getCategoryDetailId());
                if (categoryDetail != null) {
                    statusResp.setCategoryDetailName(categoryDetail.getName());
                }

                return statusResp;
            }).collect(Collectors.toList());

            loanAmountResp.setStatusRespList(statusRespList);
        }

        return CommonResult.success(loanAmountResp);
    }

    @Override
    public ResponseResult list(Integer pageNum, Integer pageSize, Integer orgId, String searchStr) {
        LambdaQueryWrapper<SmsWnsStudentLoanAmount> queryWrapper = new LambdaQueryWrapper<SmsWnsStudentLoanAmount>()
                .orderByDesc(SmsWnsStudentLoanAmount::getCreateTime);

        if (orgId != null) {
            List<String> userIdList = orgUserStuUtil.getUserIdListByOrgId(orgId);
            queryWrapper.in(SmsWnsStudentLoanAmount::getUserId, userIdList.isEmpty() ? Collections.singletonList("") : userIdList);
        }

        if (!isNullOrEmpty(searchStr)) {
            List<String> stuIdList = orgUserStuUtil.getStuIdListBySearchStr(searchStr);
            queryWrapper.in(SmsWnsStudentLoanAmount::getStuId, stuIdList.isEmpty() ? Collections.singletonList("") : stuIdList);
        }

        Page<SmsWnsStudentLoanAmount> page = new Page<>(pageNum, pageSize);
        this.page(page, queryWrapper);
        List<SmsWnsStudentLoanAmountResp> loanAmountRespList = page.getRecords().stream().map(loanAmount -> {
            SmsWnsStudentLoanAmountResp loanAmountResp = new SmsWnsStudentLoanAmountResp();
            BeanUtils.copyProperties(loanAmount, loanAmountResp);

            SmsStudentInfo studentInfo = smsStudentInfoMapper.selectById(loanAmount.getStuId());
            if (studentInfo != null) {
                loanAmountResp.setStudentInfo(studentInfo);
            }

            return loanAmountResp;
        }).collect(Collectors.toList());

        return CommonResult.success(loanAmountRespList, (int) page.getTotal());
    }

    @Override
    @Async
    public Future<ResponseResult> exportLoanAmountList(StudentLoanAmountExportReq exportReq, HttpServletResponse response) {
        LambdaQueryWrapper<SmsWnsStudentLoanAmount> queryWrapper = new LambdaQueryWrapper<SmsWnsStudentLoanAmount>()
                .orderByDesc(SmsWnsStudentLoanAmount::getCreateTime);

        // 组织id不为空, 则查询组织下的所有学生
        if (exportReq.getOrgId() != null) {
            List<String> userIdList = orgUserStuUtil.getUserIdListByOrgId(exportReq.getOrgId());
            queryWrapper.in(SmsWnsStudentLoanAmount::getUserId, userIdList.isEmpty() ? Collections.singletonList("") : userIdList);
        }

        // 学生id集合不为空, 则查询选中学生
        if (exportReq.getStuIdList() != null && !exportReq.getStuIdList().isEmpty()) {
            queryWrapper.in(SmsWnsStudentLoanAmount::getStuId, exportReq.getStuIdList());
        }

        // 查询学生助学贷款
        List<SmsWnsStudentLoanAmount> studentLoanAmountList = this.list(queryWrapper);

        try {
            // 声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            // 获取sheet页数
            double sheetNum = Math.ceil((double) studentLoanAmountList.size() / PER_SHEET_NUM);
            for (int k = 0; k < sheetNum; k++) {
                // 生成一个 sheet页,设置 sheet页 名称为 "学生助学金使用情况导出表"
                HSSFSheet sheet = workbook.createSheet("学生助学金使用情况导出表" + (k + 1));
                // 设置表格列宽度为 12
                sheet.setDefaultColumnWidth(12);

                // 设置单元格的显示样式
                HSSFCellStyle cellStyle = workbook.createCellStyle();
                cellStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                // 设置单元格字体
                HSSFFont font = workbook.createFont();
                font.setFontHeightInPoints((short) 10); // 字号
                font.setBold(true); // 加粗
                cellStyle.setFont(font);

                // 创建第一行表头
                HSSFRow headRow = sheet.createRow(0);
                // 设置第一行数据
                int fixColumnNum = 9; // 固定列数
                int columnNum = fixColumnNum + 1; // 列数
                for (int i = 0; i < columnNum; i++) {
                    // 创建一个单元格
                    HSSFCell cell = headRow.createCell(i);
                    cell.setCellStyle(cellStyle);

                    String columnName = "";
                    switch (i) {
                        case 0:
                            columnName = "序号";
                            break;
                        case 1:
                            columnName = "年级名";
                            break;
                        case 2:
                            columnName = "专业名";
                            break;
                        case 3:
                            columnName = "班级名";
                            break;
                        case 4:
                            columnName = "学生姓名";
                            break;
                        case 5:
                            columnName = "学号";
                            break;
                        case 6:
                            columnName = "贷款余额";
                            break;
                        case 7:
                            columnName = "已使用金额";
                            break;
                        case 8:
                            columnName = "核销金额";
                            break;
                        default:
                            columnName = "缴费计划名+缴费项: 贷款分配金额";
                    }

                    // 创建一个内容对象
                    HSSFRichTextString text = new HSSFRichTextString(columnName);
                    // 将内容对象的文字内容写入到单元格中
                    cell.setCellValue(text);
                }

                // 设置内容
                int range = SmsSignUpCommonConstant.PER_SHEET_NUM;
                // 如果是最后一个 sheet 页, 修改 range 值
                if (k + 1 == sheetNum) {
                    range = studentLoanAmountList.size() - SmsSignUpCommonConstant.PER_SHEET_NUM * k;
                }
                // 设置其他行数据
                for (int i = 0; i < range; i++) {
                    // 获取学生数据
                    SmsWnsStudentLoanAmount loanAmount = studentLoanAmountList.get(PER_SHEET_NUM * k + i);
                    SmsStudentInfo studentInfo = smsStudentInfoMapper.selectById(loanAmount.getStuId());

                    // 设置数据
                    // 创建一行
                    HSSFRow row = sheet.createRow(i + 1);
                    // 序号
                    row.createCell(0).setCellValue(new HSSFRichTextString(String.valueOf(i + 1)));
                    // 设置除序号外其他数据
                    for (int j = 1; j < columnNum; j++) {
                        String data = "";
                        switch (j) {
                            case 1: // 年级名
                                data = studentInfo.getStuGrade();
                                break;
                            case 2: // 专业名
                                data = studentInfo.getStuMajor();
                                break;
                            case 3: // 班级名
                                data = studentInfo.getStuClass();
                                break;
                            case 4: // 学生姓名
                                data = studentInfo.getStuName();
                                break;
                            case 5: // 学号
                                data = studentInfo.getStuNo();
                                break;
                            case 6: // 贷款余额
                                data = loanAmount.getLoanAmount().toString();
                                break;
                            case 7: // 已使用金额
                                data = loanAmount.getUsedAmount().toString();
                                break;
                            case 8: // 核销金额
                                data = loanAmount.getWriteOffAmount().toString();
                                break;
                            default: // 其他
                                List<String> statusIdList = JSON.parseArray(loanAmount.getStatusIdList(), String.class);
                                List<SmsWnsChargePlanStudentStatus> studentStatusList = smsWnsChargePlanStudentStatusMapper.selectBatchIds(statusIdList);
                                for (int l = 0; l < studentStatusList.size(); l++) {
                                    SmsWnsChargePlanStudentStatus studentStatus = studentStatusList.get(l);

                                    StringBuilder sbData = new StringBuilder();

                                    SmsWnsChargePlan plan = smsWnsChargePlanMapper.selectAllById(studentStatus.getPlanId());
                                    if (plan != null) {
                                        sbData.append(plan.getName());
                                    }
                                    if (studentStatus.getCategoryDetailId() != null) {
                                        SmsWnsChargeCategoryDetail detail = smsWnsChargeCategoryDetailMapper.selectAllById(studentStatus.getCategoryDetailId());
                                        if (detail != null) {
                                            sbData.append(detail.getName()).append(": ").append(studentStatus.getGrantAmount());
                                        }
                                    }

                                    row.createCell(j + l).setCellValue(new HSSFRichTextString(sbData.toString()));
                                }

                        }
                        if (j < fixColumnNum) {
                            row.createCell(j).setCellValue(new HSSFRichTextString(data == null ? "" : data));
                        }
                    }
                }
            }

            // 设置 response
            // response.reset();
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("学生助学金使用情况导出表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("学生助学金使用情况导出表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
            // 刷新缓冲
            response.flushBuffer();
            // workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);
            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return null;
    }

    @Override
    public ResponseResult detail(String id) {
        // 校验学生助学贷款信息是否存在
        SmsWnsStudentLoanAmount studentLoanAmount = this.getById(id);
        if (studentLoanAmount == null) {
            return CommonResult.failed(CommonCodeEnum.WNS_STUDENT_LOAN_AMOUNT_NOT_EXIST);
        }

        SmsWnsStudentLoanAmountResp loanAmountResp = new SmsWnsStudentLoanAmountResp();
        BeanUtils.copyProperties(studentLoanAmount, loanAmountResp);

        SmsStudentInfo studentInfo = smsStudentInfoMapper.selectById(studentLoanAmount.getStuId());
        if (studentInfo != null) {
            loanAmountResp.setStudentInfo(studentInfo);
        }

        if (!isNullOrEmpty(studentLoanAmount.getStatusIdList())) {
            List<String> statusIdList = JSON.parseArray(studentLoanAmount.getStatusIdList(), String.class);
            List<SmsWnsChargePlanStudentStatus> studentStatusList = smsWnsChargePlanStudentStatusMapper.selectBatchIds(statusIdList);

            List<SmsWnsChargePlanStudentStatusResp> statusRespList = studentStatusList.stream().map(status -> {
                SmsWnsChargePlanStudentStatusResp statusResp = new SmsWnsChargePlanStudentStatusResp();
                BeanUtils.copyProperties(status, statusResp);

                SmsWnsChargePlan plan = smsWnsChargePlanMapper.selectAllById(status.getPlanId());
                if (plan != null) {
                    statusResp.setPlanName(plan.getName());
                }

                SmsWnsChargeCategory chargeCategory = smsWnsChargeCategoryMapper.selectAllById(status.getCategoryId());
                if (chargeCategory != null) {
                    statusResp.setCategory(chargeCategory);
                }

                SmsWnsChargeCategoryDetail categoryDetail = smsWnsChargeCategoryDetailMapper.selectAllById(status.getCategoryDetailId());
                if (categoryDetail != null) {
                    statusResp.setCategoryDetailName(categoryDetail.getName());
                }

                return statusResp;
            }).collect(Collectors.toList());

            loanAmountResp.setStatusRespList(statusRespList);
        }

        return CommonResult.success(loanAmountResp);
    }

    @Override
    public ResponseResult update(SmsWnsStudentLoanAmountReq req) {
        if (isNullOrEmpty(req.getId(), req.getLoanAmount())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        // 校验学生助学贷款信息是否存在
        SmsWnsStudentLoanAmount studentLoanAmount = this.getById(req.getId());
        if (studentLoanAmount == null) {
            return CommonResult.failed(CommonCodeEnum.WNS_STUDENT_LOAN_AMOUNT_NOT_EXIST);
        }

        // 修改贷款余额
        studentLoanAmount.setLoanAmount(req.getLoanAmount());
        this.updateById(studentLoanAmount);

        return CommonResult.success(CommonResult.success());
    }

    @Override
    @Async
    public Future<ResponseResult> feesRecordBatchAdd(LoanBatchAddReq req, String userId) {
        // 1. 校验参数
        if (req.getLoanAddReqList().isEmpty()) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }

        // 2. 创建导入任务
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setTaskName(TaskNameExample.TASK_NAME_STUDENT_LOAN_WRITE_OFF_AMOUNT_IMPORT);
        smsImportTask.setUserId(userId);
        smsImportTask.setStatus(TASK_STATUS_DOING); // 任务状态 0:进行中
        smsImportTask.setTaskType(TaskTypeConstant.TASK_TYPE_STUDENT_LOAN_WRITE_OFF_AMOUNT_IMPORT);
        smsImportTaskMapper.insert(smsImportTask);
        String taskId = smsImportTask.getId();
        if (isNullOrEmpty(taskId)) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }

        // 3. 获取导入数据循环导入
        List<LoanAddReq> loanAddReqList = req.getLoanAddReqList();
        int OFFSET_ROW = 1; // 初始化行数
        int taskStatus = TASK_STATUS_DONE; // 任务状态: 完成
        for (int i = 0; i < loanAddReqList.size(); i++) {
            // 3.1 开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = platformTransactionManager.getTransaction(dt);
            try {
                // 3.2 获取本条导入数据
                LoanAddReq loanAddReq = loanAddReqList.get(i);

                // 3.3 校验参数并获取导入信息
                // 必填字段验证(学生学号、身份证号、姓名、核销金额)
                if (isNullOrEmpty(loanAddReq.getStuNo(), loanAddReq.getStuIdCard(), loanAddReq.getName(), loanAddReq.getWriteOffAmount())) {
                    platformTransactionManager.rollback(status);
                    createImportTaskDetail(isNullOrEmpty(loanAddReq.getStuNo()) ? "" : loanAddReq.getStuNo(), isNullOrEmpty(loanAddReq.getName()) ? "" : loanAddReq.getName(), taskId, REASON_INVALID_PARAM, String.valueOf(i + OFFSET_ROW));
                    taskStatus = TASK_STATUS_ERR;
                    continue;
                }

                // 根据学号、身份证号匹配学生
                List<SmsStudentInfo> studentInfoList = smsStudentInfoMapper.selectList(new LambdaQueryWrapper<SmsStudentInfo>()
                        .eq(SmsStudentInfo::getStuNo, loanAddReq.getStuNo()) // 学号
                        .eq(SmsStudentInfo::getStuIdCard, loanAddReq.getStuIdCard()) // 身份证号
                        .eq(SmsStudentInfo::getStuName, loanAddReq.getName())); // 姓名
                if (studentInfoList.size() != 1) { // 学籍信息不存在
                    platformTransactionManager.rollback(status);
                    createImportTaskDetail(loanAddReq.getStuNo(), loanAddReq.getName(), taskId, REASON_STUDENT_NOT_EXIST, String.valueOf(i + OFFSET_ROW));
                    taskStatus = TASK_STATUS_ERR;
                    continue;
                }
                SmsStudentInfo studentInfo = studentInfoList.get(0);

                // 校验学生助学金额账户是否存在
                SmsWnsStudentLoanAmount studentLoanAmount = this.getOne(new LambdaQueryWrapper<SmsWnsStudentLoanAmount>()
                        .eq(SmsWnsStudentLoanAmount::getStuId, studentInfo.getId()));
                if (studentLoanAmount == null) {
                    platformTransactionManager.rollback(status);
                    createImportTaskDetail(loanAddReq.getStuNo(), loanAddReq.getName(), taskId, REASON_STUDENT_LOAN_AMOUNT_NOT_EXIST, String.valueOf(i + OFFSET_ROW));
                    taskStatus = TASK_STATUS_ERR;
                    continue;
                }

                // 添加核销金额
                studentLoanAmount.setWriteOffAmount(studentLoanAmount.getWriteOffAmount().add(loanAddReq.getWriteOffAmount()));

                // 将学生贷款余额清零
                studentLoanAmount.setLoanAmount(BigDecimal.ZERO);

                this.updateById(studentLoanAmount);

                // 添加核销金额记录
                SmsWnsStudentLoanAmountRecord loanAmountRecord = new SmsWnsStudentLoanAmountRecord();
                loanAmountRecord.setLoanId(studentLoanAmount.getId());
                loanAmountRecord.setUserId(studentLoanAmount.getUserId());
                loanAmountRecord.setStuId(studentInfo.getId());
                loanAmountRecord.setType(STUDENT_LOAN_AMOUNT_RECORD_TYPE_WRITE_OFF_AMOUNT);
                loanAmountRecord.setAmount(loanAddReq.getWriteOffAmount());
                if (!isNullOrEmpty(loanAddReq.getDescription())) {
                    loanAmountRecord.setNote(loanAddReq.getDescription());
                }
                smsWnsStudentLoanAmountRecordMapper.insert(loanAmountRecord);

                // 将本笔核销金额计入流水
                SmsWnsChargePaymentRecord paymentRecord = new SmsWnsChargePaymentRecord();
                paymentRecord.setType(CHARGE_PAYMENT_RECORD_TYPE_WRITE_OFF);
                paymentRecord.setMode(CHARGE_PAYMENT_RECORD_MODE_WRITE_OFF);
                paymentRecord.setEventId(loanAmountRecord.getId()); // 核销金额记录id
                paymentRecord.setUserId(studentLoanAmount.getUserId());
                paymentRecord.setStuId(studentInfo.getId());
                paymentRecord.setPaymentAmount(loanAddReq.getWriteOffAmount());
                paymentRecord.setPaymentTime(new Date());
                paymentRecord.setNotes(CHARGE_PAYMENT_RECORD_TYPE_DES_WRITE_OFF);
                smsWnsChargePaymentRecordMapper.insert(paymentRecord);

                // 3.5 提交事务
                platformTransactionManager.commit(status);
            } catch (Exception e) {
                e.printStackTrace();
                // 捕捉到异常回滚事务
                platformTransactionManager.rollback(status);
            } finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    platformTransactionManager.commit(status);
                }
            }
        }

        // 4. 更新任务状态为已结束
        smsImportTask.setStatus(taskStatus);
        smsImportTaskMapper.updateById(smsImportTask);

        return null;
    }

    /**
     * 创建错误记录
     *
     * @param no     学号
     * @param name   姓名
     * @param taskId 任务id
     * @param reason 错误原因
     * @param row    错误行数
     */
    private void createImportTaskDetail(String no, String name, String taskId, String reason, String row) {
        SmsImportTaskDetail smsImportTaskDetail = new SmsImportTaskDetail();
        smsImportTaskDetail.setTaskId(taskId); // 任务id
        smsImportTaskDetail.setFailReason(reason); // 错误原因
        smsImportTaskDetail.setFailName(name); // 姓名
        smsImportTaskDetail.setFailNo(no); // 学号
        smsImportTaskDetail.setFailRow(row); // 错误行数
        smsImportTaskDetailMapper.insert(smsImportTaskDetail);
    }
}
